/* # TODO

- make the diagram the right size for the PDF

# OBJECTS TODO

- ray head is contained in box and is not fixed length
  - Add a rect-point constraint (or just use inRange?)
- rays don't overlap other rays (or segments)
- Maybe it would make more sense to sample in range of the box, rather than the canvas, and then optimize?? Can that be customizable in Style?

# LABELS TODO

- make `m` and `s` labels better (esp placing above segment)
- labels don't pairwise overlap
  - nothing overlaps the E^2 label (no other labels or primitives)
- sometimes the labels end up on TOP of the points due to the distance objective not being signed -- fix that
- account for label size in rect-label constraint (doesn't deal w/ non-square labels)

*/

Colors {
    -- Keenan palette
    Colors.black = rgba(0.0, 0.0, 0.0, 1.0)

    Colors.darkpurple = rgba(0.549,0.565,0.757, 1.0)
    Colors.purple2 = rgba(0.106, 0.122, 0.54, 0.2)
    Colors.lightpurple = rgba(0.816,0.824, 0.902, 1.0)

    Colors.verylightpurple = rgba(0.953, 0.957, 0.977, 1.0)
    Colors.purple3 = rgba(0.557, 0.627, 0.769, 1.0)

    Colors.midnightblue = rgba(0.14, 0.16, 0.52, 1.0)
    Colors.lightslategray = rgba(0.50, 0.51, 0.69, 1.0)
    Colors.silver = rgba(0.71, 0.72, 0.79, 1.0)
    Colors.gainsboro = rgba(0.87, 0.87, 0.87, 1.0)

    Colors.darkgray = rgba(0.1, 0.1, 0.1, 1.0)
    Colors.mediumgray = rgba(0.5, 0.5, 0.5, 1.0)
    Colors.gray = rgba(0.8, 0.8, 0.8, 1.0)
    Colors.red = rgba(1.0, 0.0, 0.0, 1.0)
    Colors.pink = rgba(1.0, 0.4, 0.7, 1.0)
    Colors.yellow = rgba(1.0, 1.0, 0.0, 1.0)
    Colors.orange = rgba(1.0, 0.6, 0.0, 1.0)
    Colors.lightorange = rgba(1.0, 0.6, 0.0, 0.25)
    Colors.green = rgba(0.0, 1.0, 0.0, 1.0)
    Colors.blue = rgba(0.0, 0.0, 1.0, 1.0)
    Colors.sky = rgba(0.325, 0.718, 0.769, 1.0)
    Colors.lightsky = rgba(0.325, 0.718, 0.769, 0.25)
    Colors.lightblue = rgba(0.0, 0.0, 1.0, 0.25)
    Colors.cyan = rgba(0.0, 1.0, 1.0, 1.0)
    Colors.purple = rgba(0.5, 0.0, 0.5, 1.0)
    Colors.white = rgba(1.0, 1.0, 1.0, 1.0)
    Colors.none = rgba(0.0, 0.0, 0.0, 0.0)
    Colors.bluegreen = rgba(0.44, 0.68, 0.60, 1.0)
}

const {
    const.pi = 3.14159
    const.arrowheadSize = 0.65
    const.strokeWidth = 1.75
    const.textPadding = 7.0
    const.textPadding2 = 25.0
    const.repelWeight = 0.0
    const.repelWeight2 = 0.0
    const.fontSize = "18pt"
    const.containPadding = 50.0
    const.rayLength = 100.0
    const.pointSize = 4.0
    const.pointStroke = 0.0
    const.thetaRadius = 40.0

    const.label = "E^2"
    const.text = Text {
	x : (const.dim / 2.0) - const.textPadding2
	y : (const.dim / 2.0) - const.textPadding2
	string : const.label
	fontSize : const.fontSize
    }

    const.dim = 400.0

    -- inner: #f3f4f9, outer: #8e93c4
    const.plane = Rectangle {
    	    angle : 0.0
	    color : Colors.verylightpurple
	    strokeColor : Colors.purple3
	    strokeWidth : 2.0
	    x : 0.0
	    y : 0.0
	    w : const.dim
	    h : const.dim
    }

   const.textLayering = const.text above const.plane
}

Point p {
      p.x = ?
      p.y = ?
      p.vec = [p.x, p.y]
      p.tup = (p.x, p.y)

       p.shape = Circle {
         x : get(p.vec, 0)
	 y : get(p.vec, 1)
         r : const.pointSize
	 color : Colors.black
	 strokeWidth : 0.0
	 strokeColor : Colors.black
       }

       p.text = Text {
         x : ?
	 y : ?
	 string : p.label
	 rotation : 0.0
	 color : Colors.black
	 fontSize : const.fontSize
       }

       p.labelFnMargin = ensure atDist(p.shape, p.text, const.textPadding)
       -- TODO: the problem is that this ensures the padding is const? Or is > padding okay?
       -- There's a choice of whether to put padding on the point or the text for containment
       p.posFn = ensure contains(const.plane, p.shape, const.containPadding)
       p.labelFn = ensure contains(const.plane, p.text, 0.0)

       p.layering1 = p.shape above const.plane
       p.layering2 = p.text above const.plane
}

Segment e
where e := MkSegment(p, q)
with Point p; Point q {
     e.vec = [q.x - p.x, q.y - p.y]

     e.color = Colors.black

     e.shape = Line {
     	     startX : p.shape.x
     	     startY : p.shape.y
     	     endX : q.shape.x
     	     endY : q.shape.y
	     color : e.color
	     thickness : const.strokeWidth
	     stroke : "none"
	     style : "solid"
     }

     e.layering1 = p.shape above e.shape
     e.layering2 = q.shape above e.shape

     LOCAL.labelAvoidFn_p = encourage repel(e.shape, p.text, const.repelWeight)
     LOCAL.labelAvoidFn_q = encourage repel(e.shape, q.text, const.repelWeight)

     e.layering = e.shape above const.plane
}

-- TODO: Take the altitude at a particular angle that happens to be right
-- Might not need to specify the angle if we know the triangle's right
Segment e
where e := Altitude(t, theta); Right(theta); theta := InteriorAngle(q, p, r) -- `p` is the point of the angle
with Triangle t; Angle theta; Point p; Point q; Point r {

     e.color = Colors.black
     e.proj_pt = project(q.tup, p.tup, r.tup)

     e.shape = Line {
     	     startX : p.x
     	     startY : p.y
     	     endX : get(e.proj_pt, 0)
     	     endY : get(e.proj_pt, 1)
	     style : "dashed"
	     color : e.color
	     thickness : const.strokeWidth
	     stroke : "none"
     }

     -- TODO: layering
}

-- Set the location of an endpoint of an altitude to be the result of the altitude on the edge
Point p
with Segment e; Triangle t; Angle theta
where p := Endpoint(e); e := Altitude(t, theta) {

      override p.x = get(e.proj_pt, 0)
      override p.y = get(e.proj_pt, 1)
}

-- Special case for KL
Point p
with Segment ba; Segment cp; Point a; Point b; Point c
where ba := MkSegment(b, a); On(p, ba); cp := MkSegment(c, p); Perpendicular(cp, ba) {

      -- BA is the existing segment; C is an existing point that defines the angle
      -- p's location is really another altitude of the angle ACB
      override p.tup = project(a.tup, c.tup, b.tup) 
      override p.x = get(p.tup, 0)
      override p.y = get(p.tup, 1)
}

Triangle t
where t := MkTriangle(p, q, r)
with Point p; Point q; Point r {
     t.color = setOpacity(Colors.darkpurple, 0.4)

     -- TODO: layer all labels on top of filled shapes
     t.shape = Curve {
     	     pathData : triangle(p.shape.x, p.shape.y, q.shape.x, q.shape.y, r.shape.x, r.shape.y)
	     strokeWidth : 0.0
	     fill : t.color
	     color : Colors.black
	     rotation : 0.0
     }

     t.layering = t.shape above const.plane
}

-- Should the rectangle be constructed from the points, or vice versa?
Rectangle R
where R := MkRectangle(p, q, r, s) 
with Point p; Point q; Point r; Point s {
     R.color = setOpacity(Colors.blue, 0.2)

     R.shape = Curve {
     	     pathData : rectangle(p.x, p.y, q.x, q.y, r.x, r.y, s.x, s.y)
	     strokeWidth : const.strokeWidth
	     fill : R.color
	     color : Colors.black
	     rotation : 0.0
     }

     R.layering = R.shape above const.plane
}

-- We don't know if the points in the triangle actually include the points in the square or not
-- TODO: this doesn't seem to match -- and the matches take way too long!!

-- Square S
-- where S := MkSquare(p, q, r, s); Disjoint(S, T); T := MkTriangle(a, b, c)
-- with Point p; Point q; Point r; Point s; Triangle T; Point a; Point b; Point c {

-- Need overrides because Square <: Rectangle

Square S
where S := MkSquare(p, q, r, s)
with Point p; Point q; Point r; Point s {

     -- Assuming (p,q) are the segment of a triangle
     -- TODO: this should really do that match in Style...
     -- and r,s are the other two points of the square

    override S.color = setOpacity(Colors.midnightblue, 0.4)

    S.path = squareAt(p.tup, q.tup)

    override S.shape = Curve {
	    pathData : polygonFromPoints(S.path)
	    -- Assumes that the last two points are the new corners (r, s) that need to be set
	    strokeWidth : const.strokeWidth
	    fill : S.color
	    color : Colors.black
	    rotation : 0.0
    }

    -- Position the points at the corner of the square
    override r.tup = get(S.path, 2)
    override r.x = get(r.tup, 0)
    override r.y = get(r.tup, 1)

    override s.tup = get(S.path, 3)
    override s.x = get(s.tup, 0)
    override s.y = get(s.tup, 1)
}

-- These more specific matches are so we can figure out which third point of the triangle to push the square away from
-- Note: order of the variables really matters!

Square S
where S := MkSquare(p, q, r, s); Disjoint(S, T); T := MkTriangle(c, q, p)
with Point p; Point q; Point r; Point s; Triangle T; Point c {

    override S.path = squareAt(p.tup, q.tup, c.tup)
}

Square S
where S := MkSquare(p, q, r, s); Disjoint(S, T); T := MkTriangle(q, p, c)
with Point p; Point q; Point r; Point s; Triangle T; Point c {

    override S.path = squareAt(p.tup, q.tup, c.tup)
}

Square S
where S := MkSquare(p, q, r, s); Disjoint(S, T); T := MkTriangle(p, c, q)
with Point p; Point q; Point r; Point s; Triangle T; Point c {

    override S.path = squareAt(p.tup, q.tup, c.tup)
}

Angle theta
where theta := InteriorAngle(q, p, r)
with Point p; Point q; Point r {

     theta.radius = const.thetaRadius
     -- TODO: always take the acute angle, not the obtuse angle
     theta.arcPath = arcPathEuclidean(p.vec, q.vec, r.vec, theta.radius, "Closed")

     theta.shape = Curve {
     		 pathData : polygonFromPoints(theta.arcPath)
		 strokeWidth : const.strokeWidth
		 color : Colors.darkpurple
		 fill : setOpacity(Colors.white, 0.5)
     }

     theta.layering1 = theta.shape above const.plane
     theta.layering2 = theta.shape below p.shape
     theta.layering3 = theta.shape below q.shape
     theta.layering4 = theta.shape below r.shape

     -- TODO: or could be minimum constraint function
     theta.sizeFn = encourage repel(q.shape, r.shape, 100.0)
}

Angle theta
where theta := InteriorAngle(q, p, r); Right(theta)
with Point p; Point q; Point r {

      theta.perpSize = 13.0

      override theta.shape = Curve {
      		 pathData : perpPath(q.tup, p.tup, r.tup, theta.perpSize)
      		 strokeWidth : 1.25
      		 color : Colors.black
      		 fill : setOpacity(Colors.white, 0.5)
      }

      theta.perpFn = ensure perpendicular(q.tup, p.tup, r.tup)

}

Ray r {
    r.length = const.rayLength
}

Point p
where p := Midpoint(s)
with Segment s {
     override p.shape.x = midpointX(s.shape)
     override p.shape.y = midpointY(s.shape)

     override p.shape.strokeWidth = 1.0
     override p.shape.color = Colors.white
     override p.shape.r = 3.2
     p.midLayering = p.shape above s.shape
}

Ray r
with Angle theta; Point x; Point y; Point z
where r := Bisector(theta); theta := InteriorAngle(y, x, z) {

      r.tail = [x.x, x.y]
      r.head = angleBisectorEuclidean(x.vec, y.vec, z.vec, r.length)

      r.shape = Line {
      	      startX : x.x
	      startY : x.y
	      -- TODO: figure out how long this should be
	      -- TODO: calculate this location properly; WRT the angle and the non-origin endpoints; this is just a heuristic
	      endX : get(r.head, 0)
	      endY : get(r.head, 1)
	      thickness : const.strokeWidth
	      color : Colors.darkpurple
      	      rightArrowhead : True
	      arrowheadSize : const.arrowheadSize
      }

      -- Bisect the arc twice more to get the bisector mark locations
      -- Throw away z coordinate for each
      theta.bisectpt1 = angleBisectorEuclidean(x.vec, y.vec, r.head, theta.radius)
      theta.bisectpt2 = angleBisectorEuclidean(x.vec, z.vec, r.head, theta.radius)
      theta.markLen = 10.0

      -- Angle bisector marks: two tick marks
      theta.bisectMark1 = Curve {
      	      pathData : makeBisectorMark(theta.bisectpt1, x.vec, theta.markLen)
      	      strokeWidth : const.strokeWidth
      	      fill : Colors.none
      	      color : Colors.darkpurple
      	      rotation : 0.0
      	      rightArrowhead : False
      	      arrowheadSize : 0.0
      }

      theta.bisectMark2 = Curve {
      	      pathData : makeBisectorMark(theta.bisectpt2, x.vec, theta.markLen)
      	      strokeWidth : const.strokeWidth
      	      fill : Colors.none
      	      color : Colors.darkpurple
      	      rotation : 0.0
      	      rightArrowhead : False
      	      arrowheadSize : 0.0
      }

      theta.layeringMark1 = theta.bisectMark1 above theta.shape
      theta.layeringMark2 = theta.bisectMark2 above theta.shape
      r.layering = r.shape above const.plane
}

Ray r
with Linelike s; Point m
where r := PerpendicularBisector(s); m := Midpoint(s) {

      r.shape = Line {
      	      startX : midpointX(s.shape)
	      startY : midpointY(s.shape)
	      endX : perpX(s.shape, r.shape.startX, r.shape.startY, r.length)
	      endY : perpY(s.shape, r.shape.startX, r.shape.startY, r.length)
	      thickness : const.strokeWidth
	      color : Colors.darkpurple
	      style : "dotted"
      	      rightArrowhead : True
	      arrowheadSize : const.arrowheadSize
      }

      r.perpSize = 10.0

      r.perpMark = Curve {
      		 pathData : perpPath(r.shape, s.shape, (r.shape.startX, r.shape.startY), r.perpSize)
		 strokeWidth : 1.25
		 color : Colors.black
		 fill : setOpacity(Colors.white, 0.5)
      }

      r.layering1 = r.shape above const.plane
      r.layering2 = r.perpMark above const.plane

      r.markLayering1 = r.perpMark below s.shape
      r.markLayering2 = r.perpMark below r.shape
      -- r.markLayering3 = r.perpMark above const.sphere
      r.markLayering4 = r.perpMark below p.shape
      r.markLayering5 = r.perpMark below q.shape
      r.markLayering6 = r.perpMark below r.shape
      r.markLayering7 = r.perpMark below m.shape

     LOCAL.labelAvoidFn_Mark = encourage repel(r.shape, m.text, const.repelWeight)
     LOCAL.labelAvoidFn_Ray = encourage repel(r.perpMark, m.text, const.repelWeight)
     LOCAL.labelAvoidFn_Seg = encourage repel(s.shape, m.text, const.repelWeight)
}

-- TODO: trying to just add a repel function on the point that's not in a segment... this might be too many repels for the ones that are in a segment though

-- TODO: should we use const.repelWeight below?

Ray r; Point p {
    LOCAL.labelAvoidFn = encourage repel(r.shape, p.text, const.repelWeight)
    LOCAL.layering = r.shape below p.shape
}

Segment s; Point p {
     -- TODO: Maybe the optimization would be faster if I used lines instead of curves for the segments?	
     LOCAL.labelAvoidFn_p = encourage repel(s.shape, p.text, const.repelWeight)
}

Triangle t; Point p {
    LOCAL.layering1 = t.shape below p.shape
    LOCAL.layering2 = t.shape below p.text
}

Square s; Point p {
    LOCAL.layering1 = s.shape below p.shape
    LOCAL.layering2 = s.shape below p.text
}

Rectangle r; Point p {
    LOCAL.layering1 = r.shape below p.shape
    LOCAL.layering2 = r.shape below p.text
}

Triangle t; Segment e {
    LOCAL.layering1 = t.shape below e.shape
}

Square s; Segment e {
    LOCAL.layering1 = s.shape below e.shape
}

Rectangle r; Segment e {
    LOCAL.layering1 = r.shape below e.shape
}

Triangle t; Angle theta {
	 LOCAL.layering = theta.shape above t.shape
}

-- ------------------------------------------------------------

-- APPENDICES BEGIN HERE

-- ------------------------------------------------------------

-- Generic Wikipedia style

-- const {
--       override const.pointSize = 0.0
--       override const.strokeWidth = 1.75
--       override const.fontSize = "14pt"
--       const.mainFontSize = "18pt"
--       const.secondaryColor = Colors.mediumgray

--       -- Don't show bounding box or plane label (but things still have to fit in the bounding box)
--       override const.plane.color = Colors.none
--       override const.plane.strokeColor = Colors.none
--       override const.label = "\\textrm{ }"

--       -- Wikipedia palette
--       Colors.lighterred = rgba(1.0, 0.851, 0.922, 1.0)
--       Colors.lighterblue = rgba(0.851, 0.914, 1.0, 1.0)
--       Colors.lighterwhite = Colors.white
-- }

-- Segment s {
-- 	override s.color = const.secondaryColor
-- 	override s.shape.thickness = const.strokeWidth
-- }

-- Triangle t {
-- 	 -- override t.color = const.red -- TODO: choose randomly
-- 	 override t.color = Colors.lighterred
-- }

-- Angle theta {
--       override theta.shape.color = const.secondaryColor

--       -- override theta.shape.fill = const.yellow -- TODO: choose randomly
-- 	 -- override theta.shape.fill = sampleUniform(const.palette)
-- 	 -- TODO: nothing for angle
-- }

-- -- Ray r
-- -- with Linelike s; Point m
-- -- where r := PerpendicularBisector(s); m := Midpoint(s) {

-- -- }

-- Ray r {
--     override r.shape.thickness = const.strokeWidth
--     override r.shape.color = Colors.black -- TODO: choose randomly
-- }

-- Ray r
-- with Angle theta; Point x; Point y; Point z
-- where r := Bisector(theta); theta := InteriorAngle(y, x, z) {
--       override theta.bisectMark1.color = const.secondaryColor
--       override theta.bisectMark2.color = const.secondaryColor
-- }

-- Ray r; Triangle t {
--     LOCAL.layering = r.shape above t.shape
-- }

-- Ray r; Angle t {
--     LOCAL.layering = r.shape above t.shape
-- }

-- Square s; Triangle t {
--     LOCAL.layering = t.shape below s.shape
-- }

-- Point p
-- with Segment s
-- where p := Midpoint(s) {
--       override p.shape.r = 0.0
--       override p.shape.strokeWidth = 0.0
-- }

-- -----------------------------------------------------

-- Specific Wikipedia style

-- Point `A` {
--       override `A`.text.fontSize = const.mainFontSize
-- }

-- Point `B` {
--       override `B`.text.fontSize = const.mainFontSize
-- }

-- Point `C` {
--       override `C`.text.fontSize = const.mainFontSize
-- }

-- Segment `AK` {
-- 	override `AK`.color = const.secondaryColor
-- }

-- Segment `KL` {
-- 	override `KL`.color = const.secondaryColor
-- }

-- Segment `AD` {
-- 	override `AD`.color = const.secondaryColor
-- }

-- Segment `CF` {
-- 	override `CF`.color = const.secondaryColor
-- }

-- -- These segments are only styled in the Byrne style

-- Segment `AB` {
-- 	override `AB`.shape.color = Colors.none
-- }

-- Segment `BC` {
-- 	override `BC`.shape.color = Colors.none
-- }

-- Segment `CA` {
-- 	override `CA`.shape.color = Colors.none
-- }

-- Segment `AL` {
-- 	override `AL`.color = Colors.none
-- }

-- Segment `BF` {
-- 	override `BF`.shape.color = Colors.none
-- }

-- Segment `DB` {
-- 	override `DB`.shape.color = Colors.none
-- }

-- -- ^ End byrne segments

-- Angle `CAB` {
--       override `CAB`.shape.color = const.secondaryColor
-- }

-- Square `BAGF` {
-- 	  override `BAGF`.color = Colors.lighterred
-- }

-- Square `ACIH` {
-- 	  override `ACIH`.color = Colors.lighterblue
-- }

-- Square `CBDE` {
-- 	  override `CBDE`.color = Colors.none
-- }

-- Rectangle `BDLK` {
-- 	  override `BDLK`.color = Colors.lighterred
-- }

-- Rectangle `CKLE` {
-- 	  override `CKLE`.color = Colors.lighterblue
-- }

-- Triangle `ABC` {
-- 	 override `ABC`.color = Colors.lighterwhite
-- }

-- Angle theta
-- where theta := InteriorAngle(q, p, r)
-- with Point p; Point q; Point r {

--       override theta.shape.fill = Colors.none
--       override theta.shape.strokeWidth = 0.0
-- }

-- Angle `CAB` {
--       override `CAB`.shape.fill = setOpacity(Colors.white, 0.5)
--       override `CAB`.shape.strokeWidth = 1.25
-- }

-- ------------------------------------------------------------

-- C82 (Byrne) colors and style
-- https://www.c82.net/blog/?id=79

-- Generic Byrne style

-- const {
--       override const.pointSize = 0.0
--       override const.strokeWidth = 0.0
--       override const.fontSize = "14pt"
--       override const.thetaRadius = 30.0
--       const.mainFontSize = "18pt"
--       const.secondaryColor = Colors.black
--       const.secondaryStrokeWidth = 4.0

--       -- Red: d52a22
--       -- Blue: 0f638f
--       -- Yellow: fbc22b
--       -- Black: black
--       -- Light yellow: 282828
--       const.red = rgba(0.835, 0.165, 0.133, 1.0)
--       const.blue = rgba(0.059, 0.388, 0.56, 1.0)
--       const.yellow = rgba(0.984, 0.761, 0.169, 1.0)
--       const.black = Colors.black
--       const.lightyellow = rgba(0.992, 0.957, 0.855, 1.0)

--       -- TODO: can't use the generic list type. (Need to change how lists are evaluated into values in evalExpr.) Instead, need to use a special Palette constructor so the backend knows that this is a list of colors
--       -- const.palette = [const.red, const.blue, const.yellow, const.black]
--       const.palette = makePalette(const.red, const.blue, const.yellow)

--       override const.plane.color = const.lightyellow
--       override const.plane.strokeWidth = 0.0
--       override const.text.string = "\\textrm{ }"
--       override const.plane.sizeY = const.dim + 50.0
--       override const.arrowheadSize = 0.5
-- }

-- -- No labels!!!

-- Point p {
--       -- Still seems to need these DOF, otherwise diagram looks cramped....
--       -- Why does the diagram keep rotating?
--       -- override p.text.x = 0.0
--       -- override p.text.y = 0.0
--       override p.text.string = "\\textrm{ }"
--       delete p.labelFnMargin
--       delete p.labelFn

--       -- TODO: how to delete all the other objfns about the labels...?
-- }

-- Segment s {
-- 	override s.color = const.secondaryColor
-- 	override s.shape.thickness = const.secondaryStrokeWidth
-- }

-- Triangle t {
-- 	 -- override t.color = const.red -- TODO: choose randomly
-- 	 override t.color = sampleUniform(const.palette)

-- }

-- Angle theta {
--       -- override theta.shape.fill = const.yellow -- TODO: choose randomly
-- 	 override theta.shape.fill = sampleUniform(const.palette)
-- }

-- -- Revert the perpmark back to the wedge...
-- Ray r
-- with Linelike s; Point m
-- where r := PerpendicularBisector(s); m := Midpoint(s) {
--      r.theta_radius = const.thetaRadius
--      -- r.theta_arcPath = arcPathEuclidean(p.vec, q.vec, r.vec, r.theta_radius)
--      r.theta_arcPath = arcPathEuclidean([r.shape.startX, r.shape.startY], [r.shape.endX, r.shape.endY], [s.shape.startX, s.shape.startY], r.theta_radius)

--      override r.perpMark = Curve {
--      		 pathData : polygonFromPoints(r.theta_arcPath)
-- 		 strokeWidth : const.strokeWidth
-- 		 color : Colors.none
-- 		 fill : sampleUniform(const.palette)
--      }
-- }

-- Ray r {
--     override r.shape.thickness = const.secondaryStrokeWidth
--     override r.shape.color = const.black -- TODO: choose randomly
-- }

-- Ray r; Triangle t {
--     LOCAL.layering = r.shape above t.shape
-- }

-- Ray r; Angle t {
--     LOCAL.layering = r.shape above t.shape
-- }

-- Point p
-- with Segment s
-- where p := Midpoint(s) {
--       override p.shape.r = 0.0
--       override p.shape.strokeWidth = 0.0
-- }

------------------------------------------------------------

-- Specific Byrne style

-- Point `A` {
--       override `A`.text.fontSize = const.mainFontSize
-- }

-- Point `B` {
--       override `B`.text.fontSize = const.mainFontSize
-- }

-- Point `C` {
--       override `C`.text.fontSize = const.mainFontSize
-- }

-- -- Since AL is dashed, we just draw AL and not AK and KL (since the dashes won't line up)
-- Segment `AK` {
-- 	override `AK`.color = Colors.none
-- 	override `AK`.shape.thickness = const.secondaryStrokeWidth
-- }

-- Segment `KL` {
-- 	override `KL`.color = Colors.none
-- 	override `KL`.shape.thickness = const.secondaryStrokeWidth
-- 	override `KL`.shape.style = "dashed"
-- }

-- Segment `AD` {
-- 	override `AD`.color = const.secondaryColor
-- 	override `AD`.shape.thickness = const.secondaryStrokeWidth
-- }

-- Segment `CF` {
-- 	override `CF`.color = const.secondaryColor
-- 	override `CF`.shape.thickness = const.secondaryStrokeWidth
-- }

-- Segment `AB` {
-- 	override `AB`.color = const.blue
-- 	override `AB`.shape.thickness = const.secondaryStrokeWidth
-- }

-- Segment `BC` {
-- 	override `BC`.color = const.red
-- 	override `BC`.shape.thickness = const.secondaryStrokeWidth
-- }

-- Segment `CA` {
-- 	override `CA`.color = const.yellow
-- 	override `CA`.shape.thickness = const.secondaryStrokeWidth
-- }

-- Segment `DB` {
-- 	override `DB`.color = const.red
-- 	override `DB`.shape.thickness = const.secondaryStrokeWidth
-- 	override `DB`.shape.style = "dashed"

--      `DB`.shape2 = Line {
--      	     startX : `DB`.shape.startX
--      	     startY : `DB`.shape.startY
--      	     endX : `DB`.shape.endX
--      	     endY : `DB`.shape.endY
-- 	     color : const.lightyellow
-- 	     thickness : const.secondaryStrokeWidth
-- 	     stroke : "none"
--      }

--      `DB`.linesLayering1 = `DB`.shape above `DB`.shape2
--      `DB`.linesLayering2 = `DB`.shape2 above const.plane
-- }

-- Segment `BF` {
-- 	override `BF`.color = const.blue
-- 	override `BF`.shape.thickness = const.secondaryStrokeWidth
-- 	override `BF`.shape.style = "dashed"

--      `BF`.shape2 = Line {
--      	     startX : `BF`.shape.startX
--      	     startY : `BF`.shape.startY
--      	     endX : `BF`.shape.endX
--      	     endY : `BF`.shape.endY
-- 	     color : const.lightyellow
-- 	     thickness : const.secondaryStrokeWidth
-- 	     stroke : "none"
--      }

--      `BF`.linesLayering1 = `BF`.shape above `BF`.shape2
--      `BF`.linesLayering2 = `BF`.shape2 above const.plane
-- }

-- Segment `AL` {
-- 	override `AL`.color = const.black
-- 	override `AL`.shape.thickness = const.secondaryStrokeWidth
-- 	override `AL`.shape.style = "dashed"

--      `AL`.shape2 = Line {
--      	     startX : `AL`.shape.startX
--      	     startY : `AL`.shape.startY
--      	     endX : `AL`.shape.endX
--      	     endY : `AL`.shape.endY
-- 	     color : const.lightyellow
-- 	     thickness : const.secondaryStrokeWidth
-- 	     stroke : "none"
--      }

--      `AL`.linesLayering1 = `AL`.shape above `AL`.shape2
--      `AL`.linesLayering2 = `AL`.shape2 above const.plane

-- }

-- Angle `CAB` {
--       override `CAB`.shape.color = Colors.none
--       override `CAB`.shape.fill = Colors.none
--       override `CAB`.shape.strokeWidth = 0.0
-- }

-- Square `BAGF` {
-- 	  override `BAGF`.color = const.red
-- }

-- Square `ACIH` {
-- 	  override `ACIH`.color = const.black
-- }

-- Square `CBDE` {
-- 	  override `CBDE`.color = const.blue
-- }

-- Rectangle `BDLK` {
-- 	  override `BDLK`.color = const.blue
-- }

-- Rectangle `CKLE` {
-- 	  override `CKLE`.color = const.yellow
-- }

-- Rectangle `BDLK`; Segment `DB` {
-- 	  LOCAL.layering = `DB`.shape2 above `BDLK`.shape
-- }

-- Square `BAGF`; Segment `BF` {
-- 	  LOCAL.layering = `BF`.shape2 above `BAGF`.shape
-- }

-- Rectangle `CKLE`; Square `CBDE` {
-- 	  LOCAL.layering = `CKLE`.shape above `CBDE`.shape
-- }

-- Triangle `ABC` {
-- 	 override `ABC`.color = Colors.none
-- }

-- Segment `DE` {
-- 	override `DE`.shape.color = Colors.none
-- }

-- -- TODO: style semantics needs to NOT run block if any of the selector names aren't in the context.
-- Segment `AB`; Segment `CF` {
-- 	LOCAL.layering = `CF`.shape above `AB`.shape
-- }

-- Segment `AL`; Segment `BC` {
-- 	LOCAL.layering = `AL`.shape above `BC`.shape
-- }

-- Segment `AD`; Segment `DB` {
-- 	LOCAL.layering = `AD`.shape above `DB`.shape
-- }

-- Angle `FBA` {
--       override `FBA`.shape.fill = const.yellow
-- }

-- Angle `CBA` {
--       override `CBA`.shape.fill = const.black
-- }

-- Angle `CBD` {
--       override `CBD`.shape.fill = const.yellow
-- }

-----------------------------------------------------

-- Specific Byrne style ONLY for staged diagrams

-- Point `A` {
--       override `A`.x = -50.0
--       override `A`.y = ?
--       -- Ensure positive (`A`.y > 0). This is so we don't have to compute the exact coordinate, but can rely on the right angle objective
--       `A`.locFn = ensure lessThanSq(-1.0 * `A`.y, 0.0)
-- }

-- Point `B` {
--       override `B`.x = 80.0
--       override `B`.y = 0.0
-- }

-- Point `C`; Point `B` {
--       override `C`.x = -80.0
--       override `C`.y = 0.0
-- }